using System;
using System.Threading;

namespace Catastrophe.Common.ThreadLock
{
	public sealed class SoftMultiTask<T>
	{
		public delegate void MultiInfo(T item, Exception ex);

		public delegate void MultiInfoTwo(int finish, int count, int success, int failed);

		private int m_opCount = 0;

		private int m_opThreadCount = 1;

		private int m_threadCount = 10;

		private int m_runStatus = 0;

		private T[] m_dataList = null;

		private Func<T, bool> m_operater = null;

		private int m_finishCount = 0;

		private int m_successCount = 0;

		private int m_failedCount = 0;

		private SimpleHybirdLock HybirdLock = new SimpleHybirdLock();

		private bool m_isRunningStop = false;

		private bool m_isQuit = false;

		private bool m_isQuitAfterException = false;

		public bool IsQuitAfterException
		{
			get
			{
				return this.m_isQuitAfterException;
			}
			set
			{
				this.m_isQuitAfterException = value;
			}
		}

		public event MultiInfo OnExceptionOccur;

		public event MultiInfoTwo OnReportProgress;

		public SoftMultiTask(T[] dataList, Func<T, bool> operater, int threadCount = 10)
		{
			this.m_dataList = dataList ?? throw new ArgumentNullException("dataList");
			this.m_operater = operater ?? throw new ArgumentNullException("operater");
			if (threadCount < 1)
			{
				throw new ArgumentException("threadCount can not less than 1", "threadCount");
			}
			this.m_threadCount = threadCount;
			Interlocked.Add(ref this.m_opCount, dataList.Length);
			Interlocked.Add(ref this.m_opThreadCount, threadCount);
		}

		public void StartOperater()
		{
			if (Interlocked.CompareExchange(ref this.m_runStatus, 0, 1) == 0)
			{
				for (int i = 0; i < this.m_threadCount; i++)
				{
					Thread thread = new Thread(new ThreadStart(ThreadBackground));
					thread.IsBackground = true;
					thread.Start();
				}
				this.JustEnded();
			}
		}

		public void StopOperater()
		{
			if (this.m_runStatus == 1)
			{
				this.m_isRunningStop = true;
			}
		}

		public void ResumeOperater()
		{
			this.m_isRunningStop = false;
		}

		public void EndedOperater()
		{
			if (this.m_runStatus == 1)
			{
				this.m_isQuit = true;
			}
		}

		private void ThreadBackground()
		{
			while (true)
			{
				bool flag = true;
				while (this.m_isRunningStop)
				{
				}
				int num = Interlocked.Decrement(ref this.m_opCount);
				if (num < 0)
				{
					break;
				}
				T val = this.m_dataList[num];
				bool flag2 = false;
				bool flag3 = false;
				try
				{
					if (!this.m_isQuit)
					{
						flag2 = this.m_operater(val);
					}
				}
				catch (Exception ex)
				{
					flag3 = true;
					this.OnExceptionOccur?.Invoke(val, ex);
					if (this.m_isQuitAfterException)
					{
						this.EndedOperater();
					}
				}
				finally
				{
					this.HybirdLock.Enter();
					if (flag2)
					{
						this.m_successCount++;
					}
					if (flag3)
					{
						this.m_failedCount++;
					}
					this.m_finishCount++;
					this.OnReportProgress?.Invoke(this.m_finishCount, this.m_dataList.Length, this.m_successCount, this.m_failedCount);
					this.HybirdLock.Leave();
				}
			}
			this.JustEnded();
		}

		private void JustEnded()
		{
			if (Interlocked.Decrement(ref this.m_opThreadCount) == 0)
			{
				this.m_finishCount = 0;
				this.m_failedCount = 0;
				this.m_successCount = 0;
				Interlocked.Exchange(ref this.m_opCount, this.m_dataList.Length);
				Interlocked.Exchange(ref this.m_opThreadCount, this.m_threadCount + 1);
				Interlocked.Exchange(ref this.m_runStatus, 0);
				this.m_isRunningStop = false;
				this.m_isQuit = false;
			}
		}
	}
}
